package com.za.plugin.transfer.form.insertupdate;

import com.za.plugin.pojo.Content;
import com.za.plugin.pojo.SqlAndParam;
import com.za.plugin.util.SqlUtil;
import com.za.plugin.util.StrUtil;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * st_point() 不支持使用变量名，只能使用值。所以每条sql都要动态获取值并替换。
 * <p>
 * 后期可以考虑 PointStyleTransfer 实现 StyleTransfer 接口
 */

public class PointStyleTransfer {

    public boolean isSupport(String sql) {
        return hasGisCalc(sql);
    }

    public static boolean hasGisCalc(String sql) {
        return sql.replaceAll("point\\s*\\(", "point(").contains("point(") ||
                sql.replaceAll("st_distance\\s*\\(", "st_distance(").contains("st_distance(");
    }

    public SqlAndParam transfer(String sql, List<ParameterMapping> parameterMappings,
                                List<ParameterMapping> parameterMappingsCopy, Object paramObj) {
        sql = sql.replaceAll("point\\s*\\(", "point(")
                .replaceAll("st_distance\\s*\\(", "st_distance(");
        sql = sql.replaceAll("st_distance\\(", "DMGEO.ST_Distance(");
        int idx = sql.indexOf("point(");
        int left = 0;
        StringBuilder sb = new StringBuilder();
        if (parameterMappings.isEmpty()) {
            parameterMappings = new ArrayList<>(parameterMappingsCopy);
        }
        while (idx >= 0) {
            sb.append(sql.substring(left, idx));
            Content expectContent = StrUtil.getExpectContent(sql, idx + 5);
            assert expectContent != null;
            String expectStr = expectContent.getExpectStr();
            List<String> segment = StrUtil.getSegment(expectStr, 0, expectStr.length());
            boolean isFirst = true;
            int count = getCountBefore(sql, idx);
            if (segment.get(0).contains("?")) {
                sb.append("dmgeo.ST_PointFromText('point(").append(getRealVal(paramObj, parameterMappingsCopy.get(count).getProperty()));
                isFirst = false;
                //后期考虑 parameterMappings.remove(count) 即可不用返回 parameterMappings 而只返回 sql，这涉及 parameterMappings
                //是值传递，但传递的是自增的拷贝，只要使用 remove或add，调用函数就能得到修改的值，而赋值，重新 new 对象就得不到
                parameterMappings = parameterMappings.stream().filter(it -> !it.getProperty().equals(parameterMappingsCopy.get(count).getProperty()))
                        .collect(Collectors.toList());
            } else {
                sb.append("dmgeo.ST_PointFromText('point(").append(segment.get(0));
            }

            if (segment.get(1).contains("?")) {
                if (isFirst) {
                    sb.append(" ").append(getRealVal(paramObj, parameterMappingsCopy.get(count).getProperty())).append(")',0)");
                    parameterMappings = parameterMappings.stream().filter(it -> !it.getProperty().equals(parameterMappingsCopy.get(count).getProperty()))
                            .collect(Collectors.toList());
                } else {
                    sb.append(" ").append(getRealVal(paramObj, parameterMappingsCopy.get(count + 1).getProperty())).append(")',0)");
                    parameterMappings = parameterMappings.stream().filter(it -> !it.getProperty().equals(parameterMappingsCopy.get(count + 1).getProperty()))
                            .collect(Collectors.toList());
                }
            } else {
                sb.append(" ").append(segment.get(1)).append(")',0)");
            }

            left = idx + expectStr.length() + 7;
            idx = sql.indexOf("point(", left);
            if (idx == -1) {
                sb.append(sql.substring(left));
            }
        }
        sql = sb.toString();
        return new SqlAndParam(sql, parameterMappings);
    }

    private String getRealVal(Object paramObj, String property) {
        if (SqlUtil.isParamMap(paramObj)) {
            MapperMethod.ParamMap<Object> paramMap = (MapperMethod.ParamMap<Object>) paramObj;
            if (paramMap.containsKey(property)) {
                return paramMap.get(property).toString();
            } else {
//                如果抛出异常可能会更好
                System.out.println("paramMap 没有真实值！！！");
            }
        } else {
            MetaObject metaObject = MetaObject.forObject(paramObj, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
            return metaObject.getValue(property).toString();
        }
        return "";
    }

    private int getCountBefore(String sql, int end) {
        int cnt = 0;
        while (end >= 0) {
            if (sql.charAt(end) == '?') {
                cnt++;
            }
            end--;
        }
        return cnt;
    }
}
